//
// x-osk.cc
//

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 */

#include "x-osk.h"


XOSK::XOSK() : mp_window_kb(0), m_moving(false)
{
    m_glade_dir_path = (Glib::file_test("img/xosk.glade", Glib::FILE_TEST_EXISTS) ? "img" : DATADIR "/xosk");
    
    mr_builder = Gtk::Builder::create_from_file(Glib::build_filename(m_glade_dir_path, "xosk.glade"));
    mr_builder->get_widget("window_kb", mp_window_kb);
    mr_builder->get_widget("button_a", mp_button_a);
    mr_builder->get_widget("button_b", mp_button_b);
    mr_builder->get_widget("button_c", mp_button_c);
    mr_builder->get_widget("button_d", mp_button_d);
    mr_builder->get_widget("button_e", mp_button_e);
    mr_builder->get_widget("button_f", mp_button_f);
    mr_builder->get_widget("button_g", mp_button_g);
    mr_builder->get_widget("button_h", mp_button_h);
    mr_builder->get_widget("button_i", mp_button_i);
    mr_builder->get_widget("button_j", mp_button_j);
    mr_builder->get_widget("button_k", mp_button_k);
    mr_builder->get_widget("button_l", mp_button_l);
    mr_builder->get_widget("button_m", mp_button_m);
    mr_builder->get_widget("button_n", mp_button_n);
    mr_builder->get_widget("button_o", mp_button_o);
    mr_builder->get_widget("button_p", mp_button_p);
    mr_builder->get_widget("button_q", mp_button_q);
    mr_builder->get_widget("button_r", mp_button_r);
    mr_builder->get_widget("button_s", mp_button_s);
    mr_builder->get_widget("button_t", mp_button_t);
    mr_builder->get_widget("button_u", mp_button_u);
    mr_builder->get_widget("button_v", mp_button_v);
    mr_builder->get_widget("button_w", mp_button_w);
    mr_builder->get_widget("button_x", mp_button_x);
    mr_builder->get_widget("button_y", mp_button_y);
    mr_builder->get_widget("button_z", mp_button_z);
    mr_builder->get_widget("button_0", mp_button_0);
    mr_builder->get_widget("button_1", mp_button_1);
    mr_builder->get_widget("button_2", mp_button_2);
    mr_builder->get_widget("button_3", mp_button_3);
    mr_builder->get_widget("button_4", mp_button_4);
    mr_builder->get_widget("button_5", mp_button_5);
    mr_builder->get_widget("button_6", mp_button_6);
    mr_builder->get_widget("button_7", mp_button_7);
    mr_builder->get_widget("button_8", mp_button_8);
    mr_builder->get_widget("button_9", mp_button_9);
    mr_builder->get_widget("button_grave", mp_button_grave);
    mr_builder->get_widget("button_minus", mp_button_minus);
    mr_builder->get_widget("button_equal", mp_button_equal);
    mr_builder->get_widget("button_bracketleft", mp_button_bracketleft);
    mr_builder->get_widget("button_bracketright", mp_button_bracketright);
    mr_builder->get_widget("button_backslash", mp_button_backslash);
    mr_builder->get_widget("button_semicolon", mp_button_semicolon);
    mr_builder->get_widget("button_apostrophe", mp_button_apostrophe);
    mr_builder->get_widget("button_comma", mp_button_comma);
    mr_builder->get_widget("button_period", mp_button_period);
    mr_builder->get_widget("button_slash", mp_button_slash);
    mr_builder->get_widget("button_tab", mp_button_tab);
    mr_builder->get_widget("button_backspace", mp_button_backspace);
    mr_builder->get_widget("button_delete", mp_button_delete);
    mr_builder->get_widget("button_return", mp_button_return);
    mr_builder->get_widget("button_home", mp_button_home);
    mr_builder->get_widget("button_end", mp_button_end);
    mr_builder->get_widget("button_space", mp_button_space);
    mr_builder->get_widget("button_left", mp_button_left);
    mr_builder->get_widget("button_right", mp_button_right);
    mr_builder->get_widget("button_left", mp_button_up);
    mr_builder->get_widget("button_right", mp_button_down);
    mr_builder->get_widget("button_quit", mp_button_quit);
    mr_builder->get_widget("button_showhide", mp_button_showhide);
    mr_builder->get_widget("togglebutton_ctrl", mp_togglebutton_ctrl);
    mr_builder->get_widget("togglebutton_alt", mp_togglebutton_alt);
    mr_builder->get_widget("togglebutton_shift", mp_togglebutton_shift);
    mr_builder->get_widget("togglebutton_capslock", mp_togglebutton_capslock);
    mr_builder->get_widget("box_row_1", mp_box_row_1);
    mr_builder->get_widget("box_row_2", mp_box_row_2);
    mr_builder->get_widget("box_row_3", mp_box_row_3);
    mr_builder->get_widget("box_row_4", mp_box_row_4);
    mr_builder->get_widget("box_row_5_showhide", mp_box_row_5_showhide);
    
    m_config_dir = Glib::build_filename(Glib::get_user_config_dir(), "x-osk");
    m_config_file = Glib::build_filename(m_config_dir, "config.conf");
    if(!config_file_load())
    {
        m_core_parms.kb_x = -1;
        m_core_parms.kb_y = -1;
        m_core_parms.dnd = true;
    }
    
    if(m_core_parms.dnd)
    {
        mp_window_kb->signal_button_release_event().connect(sigc::mem_fun(*this, &XOSK::on_window_kb_button_release_event));
        mp_window_kb->signal_motion_notify_event().connect(sigc::mem_fun(*this, &XOSK::on_window_kb_motion_notify_event));
    }
    mp_button_a->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_a_clicked));
    mp_button_b->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_b_clicked));
    mp_button_c->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_c_clicked));
    mp_button_d->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_d_clicked));
    mp_button_e->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_e_clicked));
    mp_button_f->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_f_clicked));
    mp_button_g->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_g_clicked));
    mp_button_h->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_h_clicked));
    mp_button_i->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_i_clicked));
    mp_button_j->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_j_clicked));
    mp_button_k->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_k_clicked));
    mp_button_l->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_l_clicked));
    mp_button_m->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_m_clicked));
    mp_button_n->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_n_clicked));
    mp_button_o->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_o_clicked));
    mp_button_p->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_p_clicked));
    mp_button_q->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_q_clicked));
    mp_button_r->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_r_clicked));
    mp_button_s->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_s_clicked));
    mp_button_t->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_t_clicked));
    mp_button_u->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_u_clicked));
    mp_button_v->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_v_clicked));
    mp_button_w->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_w_clicked));
    mp_button_x->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_x_clicked));
    mp_button_y->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_y_clicked));
    mp_button_z->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_z_clicked));
    mp_button_0->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_0_clicked));
    mp_button_1->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_1_clicked));
    mp_button_2->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_2_clicked));
    mp_button_3->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_3_clicked));
    mp_button_4->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_4_clicked));
    mp_button_5->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_5_clicked));
    mp_button_6->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_6_clicked));
    mp_button_7->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_7_clicked));
    mp_button_8->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_8_clicked));
    mp_button_9->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_9_clicked));
    mp_button_grave->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_grave_clicked));
    mp_button_minus->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_minus_clicked));
    mp_button_equal->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_equal_clicked));
    mp_button_bracketleft->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_bracketleft_clicked));
    mp_button_bracketright->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_bracketright_clicked));
    mp_button_backslash->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_backslash_clicked));
    mp_button_semicolon->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_semicolon_clicked));
    mp_button_apostrophe->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_apostrophe_clicked));
    mp_button_comma->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_comma_clicked));
    mp_button_period->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_period_clicked));
    mp_button_slash->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_slash_clicked));
    mp_button_tab->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_tab_clicked));
    mp_button_backspace->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_backspace_clicked));
    mp_button_delete->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_delete_clicked));
    mp_button_return->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_return_clicked));
    mp_button_home->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_home_clicked));
    mp_button_end->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_end_clicked));
    mp_button_space->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_space_clicked));
    mp_button_left->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_left_clicked));
    mp_button_right->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_right_clicked));
    mp_button_up->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_up_clicked));
    mp_button_down->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_down_clicked));
    mp_button_quit->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_quit_clicked));
    mp_button_showhide->signal_clicked().connect(sigc::mem_fun(*this, &XOSK::on_button_showhide_clicked));
    mp_togglebutton_ctrl->signal_toggled().connect(sigc::mem_fun(*this, &XOSK::on_togglebutton_ctrl_toggled));
    mp_togglebutton_alt->signal_toggled().connect(sigc::mem_fun(*this, &XOSK::on_togglebutton_alt_toggled));
    mp_togglebutton_shift->signal_toggled().connect(sigc::mem_fun(*this, &XOSK::on_togglebutton_shift_toggled));
    mp_togglebutton_capslock->signal_toggled().connect(sigc::mem_fun(*this, &XOSK::on_togglebutton_capslock_toggled));
    
    mp_window_kb->set_keep_above(true);
    mp_window_kb->set_accept_focus(false);
    mp_window_kb->set_focus_on_map(false);
    mp_window_kb->set_decorated(false);
    mp_window_kb->set_deletable(false);
    mp_window_kb->set_has_resize_grip(false);
    mp_window_kb->stick();
    if(m_core_parms.dnd)
    {
        mp_window_kb->add_events(Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON1_MOTION_MASK);
    }
    mp_window_kb->show_all();
    
    mp_window_kb->get_size(m_kb_w, m_kb_h);
    m_bsh_w = mp_button_showhide->get_allocated_width();
    m_bsh_h = mp_button_showhide->get_allocated_height();
    //cout << "kb size is " << m_kb_w << "x" << m_kb_h << endl;
    //cout << "bsh size is " << m_bsh_w << "x" << m_bsh_h << endl;
    
    if(m_core_parms.kb_x != -1)
    {
        mp_window_kb->move(m_core_parms.kb_x, m_core_parms.kb_y);
    }
}

XOSK::~XOSK()
{
}

bool  XOSK::config_file_load()
{
    if(!Glib::file_test(m_config_file, Glib::FILE_TEST_EXISTS)) return false;
    Glib::KeyFile  key_file;
    if(!key_file.load_from_file(m_config_file)) return false;
    cout << "reading parameters from " << m_config_file << endl;
    if( !key_file.has_group("core") ) return false;
    if( !key_file.has_key("core", "kb_x") ) return false;
    m_core_parms.kb_x = key_file.get_integer("core", "kb_x");
    if( !key_file.has_key("core", "kb_y") ) return false;
    m_core_parms.kb_y = key_file.get_integer("core", "kb_y");
    if( !key_file.has_key("core", "dnd") ) return false;
    m_core_parms.dnd = key_file.get_boolean("core", "dnd");
    return true;
}

void  XOSK::config_file_save()
{
    mp_window_kb->get_position(m_kb_x, m_kb_y);
    if( (m_kb_x != m_core_parms.kb_x) || (m_kb_y != m_core_parms.kb_y) )
    {
        if(!Glib::file_test(m_config_dir, Glib::FILE_TEST_IS_DIR))
            g_mkdir_with_parents(m_config_dir.c_str(), 0755); // glib, not glibmm
        Glib::KeyFile  key_file;
        key_file.set_integer("core", "kb_x", m_kb_x);
        key_file.set_integer("core", "kb_y", m_kb_y);
        key_file.set_boolean("core", "dnd", m_core_parms.dnd);
        ofstream  myfile;
        myfile.open(m_config_file.c_str());
        myfile << key_file.to_data();
        myfile.close();
        cout << "written " << m_config_file << endl;
    }
}

void  XOSK::keysym_send(uint keysym)
{
    uchar  mod_flags = 0;
    if(is_ctrl_down()) mod_flags |= FLAG_CTRL;
    if(is_alt_down()) mod_flags |= FLAG_ALT;
    if(is_shift_down()) mod_flags |= FLAG_SHIFT;
    if(is_capslock_down()) mod_flags |= FLAG_CAPSLOCK;
    
    m_xorg_lib.send_key(keysym, mod_flags);
}

void  XOSK::update_keyboard_labels()
{
    set_keyboard_letters_to_case(!is_capslock_down() && !is_shift_down());
    set_keyboard_non_letters_to_shift(!is_shift_down());
}

bool  XOSK::is_shift_down()
{
    return (mp_togglebutton_shift->get_active());
}

bool  XOSK::is_capslock_down()
{
    return (mp_togglebutton_capslock->get_active());
}

bool  XOSK::is_ctrl_down()
{
    return (mp_togglebutton_ctrl->get_active());
}

bool  XOSK::is_alt_down()
{
    return (mp_togglebutton_alt->get_active());
}

void  XOSK::set_keyboard_non_letters_to_shift(bool up)
{
    mp_button_0->set_label(up ? "0":")");
    mp_button_1->set_label(up ? "1":"!");
    mp_button_2->set_label(up ? "2":"@");
    mp_button_3->set_label(up ? "3":"#");
    mp_button_4->set_label(up ? "4":"$");
    mp_button_5->set_label(up ? "5":"%");
    mp_button_6->set_label(up ? "6":"^");
    mp_button_7->set_label(up ? "7":"&");
    mp_button_8->set_label(up ? "8":"*");
    mp_button_9->set_label(up ? "9":"(");
    mp_button_grave->set_label(up ? "`":"~");
    mp_button_minus->set_label(up ? "-":"_");
    mp_button_equal->set_label(up ? "=":"+");
    mp_button_bracketleft->set_label(up ? "[":"{");
    mp_button_bracketright->set_label(up ? "]":"}");
    mp_button_backslash->set_label(up ? "\\":"|");
    mp_button_semicolon->set_label(up ? ";":":");
    mp_button_apostrophe->set_label(up ? "'":"\"");
    mp_button_comma->set_label(up ? ",":"<");
    mp_button_period->set_label(up ? ".":">");
    mp_button_slash->set_label(up ? "/":"?");
}

void  XOSK::set_keyboard_letters_to_case(bool lowercase)
{
    mp_button_a->set_label(lowercase ? "a":"A");
    mp_button_b->set_label(lowercase ? "b":"B");
    mp_button_c->set_label(lowercase ? "c":"C");
    mp_button_d->set_label(lowercase ? "d":"D");
    mp_button_e->set_label(lowercase ? "e":"E");
    mp_button_f->set_label(lowercase ? "f":"F");
    mp_button_g->set_label(lowercase ? "g":"G");
    mp_button_h->set_label(lowercase ? "h":"H");
    mp_button_i->set_label(lowercase ? "i":"I");
    mp_button_j->set_label(lowercase ? "j":"J");
    mp_button_k->set_label(lowercase ? "k":"K");
    mp_button_l->set_label(lowercase ? "l":"L");
    mp_button_m->set_label(lowercase ? "m":"M");
    mp_button_n->set_label(lowercase ? "n":"N");
    mp_button_o->set_label(lowercase ? "o":"O");
    mp_button_p->set_label(lowercase ? "p":"P");
    mp_button_q->set_label(lowercase ? "q":"Q");
    mp_button_r->set_label(lowercase ? "r":"R");
    mp_button_s->set_label(lowercase ? "s":"S");
    mp_button_t->set_label(lowercase ? "t":"T");
    mp_button_u->set_label(lowercase ? "u":"U");
    mp_button_v->set_label(lowercase ? "v":"V");
    mp_button_w->set_label(lowercase ? "w":"W");
    mp_button_x->set_label(lowercase ? "x":"X");
    mp_button_y->set_label(lowercase ? "y":"Y");
    mp_button_z->set_label(lowercase ? "z":"Z");
}
